package thread;

import lombok.extern.slf4j.Slf4j;
import java.util.LinkedList;

/**
 * Created by lilinchao
 * Date 2022/10/20
 * Description 生产者和消费者示例
 */
@Slf4j(topic = "c.Test04")
public class GuardedTest04 {
    public static void main(String[] args) {
        //1.确定消息队列容量
        MessageQueue queue = new MessageQueue(2);
        //2.生产者线程
        for (int i = 0; i < 3; i++) {
            int id=i;
            new Thread(()->{
                try {
                    queue.put(new Message(id,"值"+id));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"生产者"+i).start();
        }
        //3.消费者线程
        new Thread(()->{
            //3.1每隔1s取一条消息
            while(true){
                try {
                    Thread.sleep(2);
                    Message message = queue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"消费者").start();
    }
}
/**
 * 消息队列类，java线程之间通信
 */
@Slf4j(topic = "c.MessageQueue")
class MessageQueue{
    //1.消息队列集合
    private LinkedList<Message> list=new LinkedList<>();
    //2.规定容量
    private int capcity;
    //3.通过构造方法规定消息队列容量
    public MessageQueue(int capcity) {
        this.capcity = capcity;
    }
    //4.获取消息
    public Message take() throws InterruptedException {
        synchronized (list) {
            //4.1判断队列是否为空
            while (list.isEmpty()) {
                log.debug("队列为空，消费者线程等待");
                list.wait();
            }
            //4.2取出队列中头元素并且返回
            Message message = list.removeFirst();
            log.debug("已消费一个信息");
            //4.3元素取出一个后需要告诉元素-1
            list.notifyAll();
            return message;
        }
    }
    //5.存入消息
    public void put(Message message) throws InterruptedException {
        synchronized (list){
            //5.1检查队列容量是否满？
            while(list.size()==capcity){
                log.debug("队列已满，生产者线程等待");
                list.wait();
            }
            //5.2将消息加入队列尾部
            list.addLast(message);
            log.debug("已生产一个信息");
            list.notifyAll();
        }
    }
}
/**
 * 邮件类，里面放邮件内容及对应id
 * ——>为了实现安全，不能set（只能通过构造方法赋初值）只能get
 */
final class Message{
    private int id;
    private Object value;
    public Message(int id, Object value) {
        this.id = id;
        this.value = value;
    }
    public int getId() {
        return id;
    }
    public Object getValue() {
        return value;
    }
    @Override
    public String toString() {
        return "Message{" +
                "id=" + id +
                ", value=" + value +
                '}';
    }
}